;**********************************************************************
;                                                                     *
;    Filename:	    navtex.asm                                        *
;    Date:          1.4.2004                                          *
;    File Version:  1.4                                               *
;                                                                     *
;    Author:        Mikael Nordman OH2AUN                             *
;    Copyright:     Mikael Nordman OH2AUN                             *
;                                                                     * 
;                                                                     *
;**********************************************************************
;                                                                     *
;    Files required:                                                  *
;                                                                     *
;                                                                     *
;                                                                     *
;**********************************************************************
;                                                                     *
;    Notes: This file is for the 16F876. It also also works with the  *
;           16F870, without a PWM, but in that case an external       *
;           divider must be provided to generate the local            *
;           oscillator frequency of 500/512 KHz                       *
;           This program has been tested with an 8 MHz crystal,       *
;           and with a 18.439(18.432) MHz crystal.                    *
;                                                                     *
;           The LCD display used is a graphics display with           *
;           240*64 pixels controlled by a Toshiba T6963C.             *
;           My display is called TOSHIBA TLX-711A-E0.                 *     
;           The graphic memory of 8 Kbyte is used for storing         *
;           the received navtex messages.                             *
;           Normal LCD text displays are of no use here since they    *
;           do not have any memory.                                   *
;           It is also possible to operate without the LCD display    *
;           and output the messages via RS232.                        *
;**********************************************************************


	list      p=16f876      	; list directive to define processor
	#include <p16f876.inc>		; processor specific variable definitions

 
	__CONFIG _CP_OFF& _WDT_OFF & _PWRTE_ON & _HS_OSC & _LVP_OFF & _BODEN_ON

; '__CONFIG' directive is used to embed configuration data within .asm file.
; The lables following the directive are located in the respective .inc file.
; See respective data sheet for additional information on configuration word.






;***** VARIABLE DEFINITIONS

ram			equ	0x20
fsr_temp        	equ 	h'7d'
w_temp        		equ 	h'7e'
status_temp   		equ 	h'7f'

cp0			equ	ram + 0
cp1			equ	ram + 1

k_down			equ	ram + 2
k_up			equ	ram + h'11' 
k_mode			equ	ram + h'1e'

fbit			equ	ram + h'29'
fbits      		equ	ram + 3
sample         		equ	ram + 4
sbits			equ	ram + 5
sbitcnt			equ	ram + 6
rx			equ	ram + 7
dx			equ	ram + 8
dx1			equ	ram + 9
dx2			equ	ram + h'a'
rxasc			equ	ram + h'32'
dx2asc			equ	ram + h'c'
errors			equ	ram + h'e'
m_delay			equ	ram + h'f'
s_delay			equ	ram + h'26'
d_delay			equ	ram + h'4e'

count1			equ	ram + h'12'
count2			equ	ram + h'13'
gchar			equ	ram + h'14'

wsave			equ	ram + h'18'

addr_lo			equ	ram + h'1f'
addr_hi			equ	ram + h'20'
gaddr_lo		equ	ram + h'48'
gaddr_hi		equ	ram + h'49'

base_lo			equ	ram + h'21'
base_hi			equ	ram + h'22'
sbase_lo		equ	ram + h'23'
sbase_hi		equ	ram + h'24'

x			equ	ram + h'15'
y			equ	ram + h'16'
row			equ	ram + h'17'
srow			equ	ram + h'25'

state			equ	ram + h'27'

samplecnt		equ	ram + h'2a'

lcdchar			equ	ram + h'b'
ch0			equ	ram + h'33'
ch1			equ	ram + h'34'
ch2			equ	ram + h'35'
ch3			equ	ram + h'36'
ch4			equ	ram + h'37'
ch5			equ	ram + h'38'
ch6			equ	ram + h'39'
ch7			equ	ram + h'3a'
ch8			equ	ram + h'3b'
ch9			equ	ram + h'3c'
ch10			equ	ram + h'3d'
ch11			equ	ram + h'3e'
ch12			equ	ram + h'3f'
ch13			equ	ram + h'40'
ch14			equ	ram + h'41'
ch15			equ	ram + h'42'
ch16			equ	ram + h'43'
ch17			equ	ram + h'44'
ch18			equ	ram + h'45'
ch19			equ	ram + h'46'

rx_i			equ	ram + h'47'
last_mode_char		equ	ram + h'4a'
mode_p			equ	ram + h'4b'
mx			equ	ram + h'4c'
my			equ	ram + h'4d'
count_i			equ	ram + h'd'

rxt			equ	h'7c'
rx0			equ	h'a0'		; A0 - BF is the serial receive buffer, 32 bytes, bank 1
rx2			equ	h'a2'		; only A0 to BF is available on 16F870, 32 bytes
rx3			equ	h'a3'
rx4			equ	h'a4'
rx6			equ	h'a6'

nmea_cmd		equ	h'70'		; describe which nmea command is beeing analysed
						; 0 = no nmea command
						; 1 = start of nmea string received ($)
						; 2 = command name received
						; 3 = apb
						; 4 = gll
						; 5 = vtg
						; 6 = control command

nmea_param		equ	h'71'		; the number of nmea parameter that has been received
						; 0 = no parameter
						; 1 = first parameter + comma/asterisk
						; 2 = second parameter + comma/asterisk
						; 3 = third + comma/asterix
						; 4 = und so weiter

eedata			equ	h'72'
eeaddr			equ	h'73'
set_mode		equ	h'74'		; indicates if the filter parameters are beeing changed
						; 0 = normal operation
						; 1 = st1
						; 2 = st2
						; 3 = st3
						; 4 = a
						; 5 = c
						; 6 = f
						; 7 = g
						; 8 = h
						; 9 = i
						; 10 = j
						; 11 = k
						; 12 = l
						; 13 = z
; PORTA bits
LCD_RESET		equ 0
RD_			equ 1
CE			equ 2
CD			equ 3
K_MODE			equ 4
WR_			equ 5

; PORTC bits
K_UP			equ 0
LO			equ 1
CPT			equ 2
LED			equ 3
K_DOWN			equ 4
LCD_MODE		equ 5
SERIAL_IN		equ 7
TRISC_MAP		equ 0xb5		; (1 | 4 | 10 |20 | 80) 10110101

; state bits
WRAP_ON			equ	0
LINE_WRAP		equ	1
SHIFT			equ	2
MSGSTATE		equ	3
RXSTATE			equ	4
NMEA_PARAM		equ	6
SCROLL_MODE		equ	7

;******************************************************************
; define the 8000 KHz (16000, 8192, 16384, 18432) crystal real frequency here !!
; 8000 KHz and 18439 KHz has been tested.
; 1 KHz accuracy needed here
;		local	crystal = d'18439250'
		local	crystal = d'8000000'
;		local	crystal = d'8192000'
		local	clock = crystal / 4
		local	if_div = clock / d'500000'
		local	pwm_cycle = if_div - 1			; pulse width modulator cycle
		local	pwm_duty  = pwm_cycle / 2
		local	if = d'518000' - clock / if_div

		if (if > d'16000')
			local capture_prescaler = d'16'
			local ccp1con_value = b'00000111'
			local samples = d'10'
			local inphase = d'5'
			local tick = d'1000'
		else
			local capture_prescaler = 4
			local ccp1con_value = b'00000110'
			local samples = d'12'
			local inphase = d'6'
			local tick = d'1200'
		endif
		local	capture_mid = clock * capture_prescaler / if
		local   capture_lo = capture_mid & d'255'
		local	capture_hi = capture_mid / d'256'
		if (capture_mid < 0x7ff)
			local capture_ofl = d'3'
		else
			local capture_ofl = d'4'
		endif
		local	timer0_prescaler = d'16'
		local	option_reg_val = B'11010011'
		local	t0div = (clock / timer0_prescaler / tick) - 1
		local	t0value = d'256' - t0div		; 1 or 0.8888 millisecond tick from timer 0
;******************************************************************
; Asynchronous serial baud rate = 4800
		local	baud = d'4800'
		local	baud_prescaler = d'16'
		local   spbrg_val = (clock / baud_prescaler / baud) - 1

;**********************************************************************
		ORG     0x000             ; processor reset vector
		clrf    PCLATH            ; ensure page bits are cleared
		movlw	ram
		movwf	FSR
 		goto    main              ; go to beginning of program

;***********************************************************************
; THE INTERRUPT ROUTINE
		ORG     0x004             ; interrupt vector location
		goto	irq_start
;******************************************************************************
;serial routine is on first program page to make jump tables easy
serial:
		movfw	nmea_cmd
		addwf	PCL, F			; jump table for nmea_status
		goto	get1bit_ret		; 0 no nmea command
		goto	get1bit_ret		; 1 start of nmea string
		goto	ser_chk_gll		; 2 check which nmea command has been received
		goto	display_gll
		goto	display_vtg
		goto	display_apb
		goto	check_cmd		; 6 control cmd 
;*******************************************************************************
display_gll:
		btfss	state, SCROLL_MODE
		call	set_gbase		; do not show gps screen in scroll mode
		btfss	state, NMEA_PARAM
		goto	get1bit_ret
		bcf	state, NMEA_PARAM
		movfw	nmea_param
		sublw	d'5'
		bnc	get1bit_ret
		movfw	nmea_param
		addwf	PCL, F
		goto	get1bit_ret	; no parameter is available
		goto	disp_lat	; latitude
		goto	disp_lat1	; N/W
		goto	disp_lon	; longitude
		goto	disp_lon1	; E/W
		goto	disp_utc	; Universal Time Coordinates
;*******************************************************************************
display_vtg:
		btfss	state, SCROLL_MODE
		call	set_gbase		; do not show gps screen in scroll mode
		btfss	state, NMEA_PARAM
		goto	get1bit_ret
		bcf	state, NMEA_PARAM
		movfw	nmea_param
		sublw	d'5'
		bnc	get1bit_ret
		movfw	nmea_param
		addwf	PCL, F
		goto	get1bit_ret	; no parameter is available
		goto	get1bit_ret	; skip first parameter
		goto	get1bit_ret	; skip second parameter
		goto	disp_track	; track
		goto	disp_track1	; True/Magnetic
		goto	disp_speed	; Speed
;*******************************************************************************
display_apb:
		btfss	state, SCROLL_MODE
		call	set_gbase		; do not show gps screen in scroll mode
		btfss	state, NMEA_PARAM
		goto	get1bit_ret
		bcf	state, NMEA_PARAM
		movfw	nmea_param
		sublw	d'14'
		bnc	get1bit_ret
		movfw	nmea_param
		addwf	PCL, F
		goto	get1bit_ret	; no parameter is available
		goto	get1bit_ret	; skip first parameter
		goto	get1bit_ret	; skip second parameter
		goto	disp_xte	; cross track error
		goto	disp_dts	; direction to steer
		goto	disp_xteu	; cross track error unit
		goto	disp_status1	; arrival circle entered
		goto	disp_status2	; perpendicular passed at waypoint
		goto	disp_bod	; bearing, origin to waypoint
		goto	disp_bod1	; true/magnetic
		goto	get1bit_ret	; skip destination waypoint id
		goto	disp_bpd	; bearing, current position to waypoint
		goto	disp_bpd1	; true/magnetic
		goto	disp_hds	; heading, direction to steer
		goto	disp_hds1	; true/magnetic
;*******************************************************************************
; mode update branch table
mode_branch:
		movfw	set_mode
		addwf	PCL, F
		goto	mode_ret
		goto	set_mode_1
		goto	set_mode_2
		goto	set_mode_3
		goto	set_mode_4
		goto	set_mode_5
		goto	set_mode_5
		goto	set_mode_5
		goto	set_mode_5
		goto	set_mode_5
		goto	set_mode_5
		goto	set_mode_5
		goto	set_mode_5
		goto	set_mode_5
set_mode_branch:
		movfw	set_mode
		addwf	PCL, F
		goto	mode_ret
		goto	set_mode_ud_st
		goto	set_mode_ud_st
		goto	set_mode_ud_st
		goto	set_mode_ud_msg_n
		goto	set_mode_ud_msg_n
		goto	set_mode_ud_msg_n
		goto	set_mode_ud_msg_n
		goto	set_mode_ud_msg_n
		goto	set_mode_ud_msg_n
		goto	set_mode_ud_msg_n
		goto	set_mode_ud_msg_n
		goto	set_mode_ud_msg_n
		goto	set_mode_ud_msg_n
;*******************************************************************************
serial_int:
		movfw	RCREG
		movwf	rxt

		btfsc	RCSTA, FERR
		goto	seri_err
		btfsc	RCSTA, OERR
		goto	seri_err

		btfsc	state, SCROLL_MODE
		goto	serial_skip
		btfsc	state, RXSTATE		; dont receive serial information during
		goto	serial_skip		; navtex reception
		movf	set_mode, W		; Mode adjustement
		bnz	serial_skip

		movf	rxt, W
		call	serial_out		; Don't get here during navtex reception.
						; There will be return stack overflow, and random crashes.
serial_int1:
		movfw	nmea_cmd
		addwf	PCL, F			; jump table for nmea_cmd
		goto	seri_get_start		; 0 no command
		goto	seri_get_cmd		; 1 start of nmea string
		goto	seri_get_param		; 2 check which nmea command has been received
		goto	seri_get_param
		goto	seri_get_param
		goto	seri_get_param
		goto	seri_get_param

seri_get_start:	
		movf	rx_i, W
		bnz	seri_add_char
		movfw	rxt
		sublw	'$'
		bz	seri_state_start
		goto	seri_add_char
seri_get_cmd:
		movfw	rx_i
		sublw	6
		bz	seri_state_cmd
		goto	seri_add_char
seri_get_param:
		movfw	rxt
		sublw	','
		bz	seri_state_param
		movfw	rxt
		sublw	'*'
		bz	seri_state_param
		goto	seri_add_char
seri_add_char:
		movfw	rxt
		sublw	8			; backspace
		bnz     seri_add_char1
		movf	rx_i, F
		bz	seri_add_char_ret
		decf	rx_i, F
		movlw	' '
		call	serial_out
		movlw	8
		call	serial_out
		goto	seri_add_char_ret
seri_add_char1:
		movfw	rx_i
		addlw	rx0
		movwf	FSR
		movfw	rxt
		movwf	INDF
		bcf	PORTC, LED

		sublw	0xa	; Line feed
		bz	seri_state_end

		movfw	rx_i
		sublw	d'31'
		bnc	seri_state_end	; Carry meaning is inverted for subtraction
		incf	rx_i, F
seri_add_char_ret:
		return

; start of NMEA command '$' 
seri_state_start:
		movlw	1
		movwf	nmea_cmd
		clrf	nmea_param
		clrf	rx_i
		goto	seri_add_char1
seri_state_cmd:
		movlw	2
		movwf	nmea_cmd
		clrf	rx_i
		return
seri_state_param:
		incf	nmea_param, F
		movfw	rx_i
		addlw	rx0
		movwf	FSR
		movfw	rxt
		movwf	INDF

		clrf	rx_i
		bsf	state, NMEA_PARAM
		bcf	PORTC, LED
		return
		
; end of command, carriage return or overflow
seri_state_end:
		bsf	PORTC, LED
		clrf	rx_i
		clrf	nmea_param
		bcf	state, NMEA_PARAM
		movf	nmea_cmd, F
		bnz	seri_state_end1
		movlw	6
		movwf	nmea_cmd		; this is a control cmd
		return		
seri_state_end1:
		clrf	nmea_cmd
		return
seri_err:
		bcf	RCSTA, CREN
		bsf	RCSTA, CREN
serial_skip:
		bcf	state, NMEA_PARAM
		clrf	rx_i
		clrf	nmea_cmd
		return

;***************************************************************************
; THE INTERRUPT ROUTINE
irq_start:
		movwf   w_temp            ; save off current W register contents
		swapf	STATUS, W         ; move status register into W register
		clrf	STATUS
		movwf	status_temp       ; save off contents of STATUS register
		movfw	FSR
		movwf   fsr_temp

		bcf	INTCON, T0IF	; Only timer0 interrupt exists
		movlw	t0value
		movwf   TMR0

		call 	samplebit
		call	checkkey

		btfsc	PIR1, RCIF      ; RCIF is cleared automagically by the HW
		call	serial_int		

		movfw	fsr_temp
		movwf	FSR
		swapf   status_temp, w    ; retrieve copy of STATUS register
		movwf	STATUS            ; restore pre-isr STATUS register contents
		swapf   w_temp, f
		swapf   w_temp, w         ; restore pre-isr W register contents
		retfie                    ; return from interrupt

;***********************************************************************************
; Timer interrupt
; Sample sitor bits every 10 ms
; Sample bitsamples every 1 ms (18 KHz IF) or  833 us (6 KHz IF)
; A new capture event occurs at 888 us (18 KHz IF) or 733 us (6KHz IF) intervals
; 00001111 is considered to be a sitor signal rising edge.
;
samplebit:
		rlf	fbits, F		; Make place for new sample

; diff = cp + not(cp_old)
		comf	cp0, F
		comf	cp1, F
		movf	cp0, W
		addwf	CCPR1L, W
		movwf	cp0
		movf	cp1, W
		btfsc	STATUS, 0
		incf	cp1, W
		addwf	CCPR1H, W
		movwf	cp1

		btfss	cp1, capture_ofl
		goto	intsam_diff
		bcf	STATUS, C		; two sample periods have been captured
		rrf	cp1, F			; divide by 2
		rrf	cp0, F

;xtal = 18432 kHz mid = (6000 Hz) 3072(0xc00), low = (5930 Hz), hi = (6070 Hz)
;xtal = 18440 kHz mid = (5777 Hz) 3191(0xc77), low = (5707 Hz), hi = (5847 Hz)
;xtal = 18439,5   mid = (5791 Hz) 3184(0xc70), low = (5720 Hz) 3223, hi = (5860 Hz) 3146
;xtal = 8000 KHz  mid = (18000 Hz) 0x6f0
; if (diff < capture) then
;	result = 0
; else
;	result = 1
; endif

intsam_diff:
		movlw	capture_hi		; middle frequency
		subwf	cp1, W			; captured frequency
		movlw	capture_lo		; middle frequency
		btfsc	STATUS, Z		; captured frequency
		subwf	cp0, W
		btfsc	STATUS, C
		goto	intsam1
		goto	intsam0
intsam0:
		bcf	fbits, 0
		goto	intsamcont
intsam1:
		bsf	fbits, 0
intsamcont:
		movfw	CCPR1L		; save the captured timer1 value
		movwf	cp0
		movfw	CCPR1H
		movwf	cp1

		decfsz	sample, F	; sample--;
		goto    setsample	; if sample != 0, try to set the sampling time 
		movlw	samples		; else, take a sample
		movwf	sample

		clrf	fbit
		movlw	8
		movwf	samplecnt
sampleloop:
		rlf	fbits, F
		btfsc	STATUS, C
		incf	fbit, F
		decfsz  samplecnt, F	; count the sum of the bits in fbits
		goto	sampleloop   

		rlf	fbits, F	; Restore the last bit from the carry flag
		rlf	sbits, F        ; make space for a new bit
		movlw	5		; Is it 1 or 0 ?
		subwf	fbit, W
		bc	sample0		; Note inversion of sampled bit AND
					; inversion of Carry flag after a SUB
sample1:
		bsf	sbits, 0
		goto	samcont
sample0:
		bcf	sbits, 0
samcont:
		incf	sbitcnt, F	; sbitcnt++

setsample:
		movlw	0xf
		subwf	fbits, W
		btfss	STATUS, Z
		return			; return if not an edge.
		movlw	inphase		; sample should be inphase, if we are in phase.
		subwf	sample, W
		bz	samret		; if sample = inphase then donothing
		bnc	saminc
		decf	sample, F	; if sample > inphase then sample--
		return
saminc:
		incf	sample, F	; if sample < inphase then sample++
samret:
		return
;***************************************************************************
; check if display should be scrolled up or down
; a key is considered pressed if all 8 samples are 0. pullup at port.
checkkey:
		decf	m_delay, F
		bnz	check_key1
		incf	s_delay, F
		movfw	d_delay
		subwf	s_delay, W
		bnz	check_key1
		clrf	s_delay
check_key1:
		rlf	k_up, F		; Make place for new sample
		btfsc	PORTC, K_UP
		goto	k_up1
		bcf	k_up, 0
		goto    k_up2
k_up1:
		bsf	k_up, 0
k_up2:
		rlf	k_down, F	; Make place for new sample
		btfsc	PORTC, K_DOWN
		goto	k_down1
		bcf	k_down, 0
		goto    k_down2
k_down1:
		bsf	k_down, 0
k_down2:

		rlf	k_mode, F	; Make place for new sample
		btfsc	PORTA, K_MODE
		goto	k_mode1
		bcf	k_mode, 0
		goto    k_mode2
k_mode1:
		bsf	k_mode, 0
k_mode2:
		return

;***************************************************************************
; THE MAIN LOOP
main:
		clrf	INDF
		incf	FSR, F
		btfss	FSR, 7
		goto	main

		bsf	k_mode, 0
		bsf	k_up, 0
		bsf	k_down,  0

		movlw	2
		movwf	d_delay

		bsf	STATUS, RP1
		clrf	EEADRH
		bcf	STATUS, RP1

		movlw	samples		; 10/12 samples per sitor bit 
		movwf	sample
; Configure timer0
; timeout = 1 ms or 833 us,
; 10/12 samples / sitor bit
		movlw	b'00011110'
		movwf	PORTA
		clrf	PORTB
		clrf	PORTC
		bsf	STATUS, RP0	; set file bank 1
		movlw	option_reg_val	; timer0 prescaler is 16
		movwf   OPTION_REG
		movlw	h'6'		; PORT A is all digital
		movwf	ADCON1
		clrf	TRISA
		bsf	TRISA, K_MODE	; Mode input
		clrf    TRISB
		movlw	TRISC_MAP
		movwf	TRISC
		bcf	STATUS, RP0	; set file bank 0

; Init Module 1 for capture of the navtex fsk period
		movlw	ccp1con_value	; Capture on every fourth or sixteenth rising edge on RC2
		movwf	CCP1CON

		bsf	T1CON, TMR1ON	; Enable timer1 at the internal clock Fosc/4

; Init Module2 for PWM at 500 KHz or 512 KHz
; This only works with 16f876-16f877. 
; 16f870-16f872 has only one ccp module, which is used for the capture function
		bsf	STATUS, RP0
		movlw	pwm_cycle	;
		movwf	PR2		; pwm cycle = (PR2 + 1)
		bcf	STATUS, RP0
		movlw	b'00001111'	; PWM mode
		movwf	CCP2CON
		movlw	pwm_duty
		movwf	CCPR2L		; Set duty cycle to about 50 %
		bsf	T2CON, TMR2ON	; TMR2 on, Prescaler=1

; Initialise the RS port for reception
; 4800 baud, 8bit, no parity
		bsf	STATUS, RP0
		movlw	spbrg_val	; define the baud rate
		movwf	SPBRG
		bsf	TXSTA, TXEN	; Enable serial transmission
		bcf	STATUS, RP0
		bcf	RCSTA, RX9
		bsf	RCSTA, SPEN	; RC7/RX, RC6/TX
		bsf	RCSTA, CREN	; Enable asynchronous continuous receive		


; Initalise the LCD display
		call	init_lcd

; Configure interrupt
; Enable the timer0 interrupt and peripheral interrupts
		movlw   B'01100000'     ; Enable peripheral and timer0 interrupt
		movwf	INTCON


; START RECEPTION
state0:
		movlw	h'97'
		call	cput		; text on, cursor blinking, graphics off

; SYNCRONISING TO THE SITOR SIGNAL
state1:
		clrf	errors
		clrf	rx
		clrf	dx
		clrf	dx1
		bcf	state, RXSTATE
		bcf	state, LINE_WRAP
		call    get1bit 	; returns with 7 latest bits in w
		sublw	0x78
		btfss   STATUS, Z   
		goto	state1		; loop in state1 until 0x78 received
state2:
		movf	set_mode, F	; Dont receive if mode change is in progress.
		bnz	state1

		bsf	state, RXSTATE
		call 	get7bits
		sublw	0x33
		btfss   STATUS, Z
		goto	state1		; 0x33 must be received here
state3:
		call	get7bits
		sublw	0x78
		btfss	STATUS, Z
		goto	state1		; 0x78 must be received here

		clrf	x
		call	set_addr	; set writing address to navtex buffer
		call	set_base	; display the navtex buffer

		bcf	state, SCROLL_MODE	; make sure nmea is displayed after navtex is finished

		movlw	h'96'
		call	cput		; text on, cursor fixed, graphics off
;***************************************************************************
; SYNCHRONISATION COMPLETE
; START RECEIVING
; GET FIRST CHARACTER
receive1:
		movf	dx1, W
		movwf	dx2
		movf	dx, W
		movwf	dx1
		bcf	PORTC, LED
		call	get7bits
		movwf	dx
		bsf	PORTC, LED

; GET SECOND CHARACTER
		call	get7bits
		movwf	rx
		sublw	0x78
		btfsc	STATUS, Z	; If IDLE received, start from first character
		goto	receive1


; Display error status
		movfw	errors
		addlw	h'a1'		; set cursor to errors + 2 lines high
		call	cput

; TRANSLATE RX to ASCII
		btfsc	state, SHIFT
		bsf	rx, 7		; set msb of rx according to shift
		movf	rx, W
		call	sitoasc
		movwf	rxasc
		bcf	rx, 7		; clear msb of RX, only needed during translation

; TRANSLATE DX2 to ASCII
		btfsc	state, SHIFT
		bsf	dx2, 7
		movf	dx2, W
		call 	sitoasc
		movwf	dx2asc
		bcf	dx2, 7

		movf	rxasc, F	; check rxasc
		btfsc	STATUS, Z
		goto 	rxmutilated	; rx zero
					; rxasc was OK, check dx2asc
chkdx2:
		movf	dx2asc, F	; check dx
		btfsc	STATUS, Z	; 
		goto	testltrs	; rx is OK dx zero
		movf	rxasc, W
		subwf	dx2asc, W
		btfsc   STATUS, Z
		goto	rxisdx		; rx = dx
		goto    bothdifferent	; dx2asc was zero
rxisdx:
		movf	errors, F
		bz	testltrs	; if rx and dx are ok
		decf	errors, F	; decrement errors until zero
		goto	testltrs
rxmutilated:
		movf	dx2, W
		movwf	rx              ; dx2 -> rx
		movf	dx2asc, W
		movwf	rxasc
		movf	rxasc, F
		btfsc	STATUS, Z
		goto	bothmutilated
testltrs:
		movf	rxasc, W
		sublw	'L'
		btfss	STATUS, Z
		goto    testfigs
		bcf	state, SHIFT
		goto	chkerr
testfigs:
		movf	rxasc, W
		sublw	'F'
		btfss	STATUS, Z	
		goto	printrx
		bsf	state, SHIFT
		goto    chkerr
bothmutilated:
bothdifferent:
		incf    errors, F	; errors++
;		goto	chkerr
		movlw	'_'
		movwf	rxasc
printrx:
		call	filter		; character is in rxasc !
chkerr:
		movf	dx2, W
		sublw	0x78		; end of transmission
		btfsc	STATUS, Z
		goto	state0

		movf	errors, W
		sublw	0x6
		btfss	STATUS, Z
		goto	receive1
		goto	state0
;**********************************************************************
; SUBROUTINES
;**********************************************************************
; WAIT UNTIL 7 NEW BITS HAVE ARRIVED
get7bits:
		bsf	INTCON, GIE     ; ENABLE GLOBAL INTERRUPT BIT
		nop
		bcf	INTCON, GIE     ; DISABLE GLOBAL INTERRUPT BIT
		movf	sbitcnt, W
		sublw	6
		bc 	get7bits
		clrf    sbitcnt
		movf	sbits, W
		andlw	0x7f		; mask bit 7 away
		bsf	INTCON, GIE     ; ENABLE GLOBAL INTERRUPT BIT
		return		

; WAIT UNTIL 1 NEW BIT HAS ARRIVED
get1bit:
		bsf	INTCON, GIE     ; ENABLE GLOBAL INTERRUPT BIT
		btfsc	PORTC, LCD_MODE ; check if LCD is present
		goto	get1bit1	; dont check buttons if there is no display
		call	mode		; check mode button
		call	scroll		; check scroll buttons
get1bit1:
		goto	serial		; check serial buffer
					; Cannot use call due to exhausted stack
get1bit_ret:
		bcf	INTCON, GIE     ; DISABLE GLOBAL INTERRUPT BIT
		movf	sbitcnt, F
		bz	get1bit
		clrf    sbitcnt
		movf	sbits, W
		andlw	0x7f		; mask bit 7 away
		bsf	INTCON, GIE     ; ENABLE GLOBAL INTERRUPT BIT
		return
;****************************************************************************

;****************************************************************************
; 6963c CONTROL ROUTINES
;****************************************************************************
; LCD pin numbering for TOSHIBA TLX-711A-E0 (uses T6963C controller)
;
;  LCD Pin ----- PIC Port
; ------------------------------------------
;  RST  (10)<--> (RA0)
;  /RD  (6) <--> (RA1)
;  /CE  (7) <--> (RA2)
;  C/D  (8) <--> (RA3)
;  /WR  (5) <--> (RA5)
; -----------------------
;  D0  (11) <--> (RB0)
;  D1  (12) <--> (RB1)
;  D2  (13) <--> (RB2)
;  D3  (14) <--> (RB3)
;  D4  (15) <--> (RB4)
;  D5  (16) <--> (RB5)
;  D6  (17) <--> (RB6)
;  D7  (18) <--> (RB7)
;  GND (2)  <--> (xxx)
; --------------------------------------------------------------
;  FG    (1)  frame ground
;  +5V   (3)  LCD logic supply
;  -7.8V (4)  LCD display contrast
;  FS    (19) font select (FS0 = 0, FS1 = 1)
;
;*******************************************************
; WAIT UNTIL LCD is READY TO RECEIVE DATA
;*******************************************************
lcd_ready:
		btfsc	PORTC, LCD_MODE ; check if LCD is present
		return
		bsf 	STATUS, RP0	; Address TRISB
		movlw 	0xff
		movwf 	TRISB		; Make Port B an input
		bcf 	STATUS, RP0	; Address PORTB
		bsf 	PORTA, WR_	; WR high
		bsf 	PORTA, CD	; CD high
lcd_ready1:
		bcf 	PORTA, RD_	; RD low
		bcf 	PORTA, CE	; CE low
		movf 	PORTB, W	; Read PORTB
		bsf 	PORTA, CE       ; CE high
		andlw 	3		; Check 2 lowest bits
		sublw 	3
		bnz 	lcd_ready1	; Wait until lcd is ready
		bsf 	PORTA, RD_
		bcf	PORTA, CD
		bsf 	STATUS, RP0
		clrf 	TRISB		; Make PORTB an output
		bcf 	STATUS, RP0
		return

;********************************************************
; Write data byte (W) to LCD module
;********************************************************
dput:
		btfsc	PORTC, LCD_MODE ; check if LCD is present
		return
		movwf	wsave
		call 	lcd_ready
		movf	wsave, W
		movwf 	PORTB           ; write data to lcd
		bcf 	PORTA, CD	; CD low
		bcf 	PORTA, WR_	; WR low
		bcf 	PORTA, CE	; CE low
		bsf 	PORTA, CE	; CE high
		return

;********************************************************
; Write command byte to lcd module
;********************************************************
cput:
		btfsc	PORTC, LCD_MODE ; check if LCD is present
		return
		movwf	wsave
		call 	lcd_ready
		movf	wsave, W
		movwf 	PORTB
		bsf 	PORTA, CD
		bcf 	PORTA, WR_
		bcf 	PORTA, CE
		bsf 	PORTA, CE
		return

;*******************************************************
; Get data byte from lcd (not verified)
;*******************************************************
;dget:
;		call lcd_ready
;		bsf STATUS, RP0         ; Address TRISB
;		movlw 0xff
;		movwf TRISB		; Make Port B an input
;		bcf STATUS, RP0		; Address PORTB
;
;		bsf PORTA, WR_		; Not write mode
;		bcf PORTA, CD		; Data mode
;		bcf PORTA, RD_		; Read Mode
;		bcf PORTA, CE		; Chip enable
;		nop
;		movfw PORTB	
;		movwf lcd_byte_in
;		bsf PORTA, CE		; Chip disable
;		bsf PORTA, RD_		; Disable Read mode
;
;		bsf STATUS, RP0
;		clrf TRISB              ; Make PORTB an output
;		bcf STATUS, RP0
;		return


;*********************************************************
; init_lcd
;*********************************************************
init_lcd:
		movlw	cr_lf
		call	see_out
		movlw	version
		call	see_out

		bsf	PORTA, LCD_RESET; clear display reset line

		call	init_gaddr	; clear the gps/mode screen
		call	clear_screen

		call	set_base	; display the navtex screen
		call	set_addr	; set navtex write address
		call	clear_screen	; clear screen
		call	set_addr	; restore navtex write address

		movlw	d'40'
		call	dput
		movlw	0
		call	dput
		movlw	h'41'		; set text area
		call	cput		; set 40 bytes per text row

		movlw	h'80'		; OR writing mode internal fonts
		call	cput

		movlw	h'a1'		; set cursor to 1 lines high
		call	cput

		movlw	0
		call	dput		; dput does not destroy W
		call	dput
		movlw	0x21
		call 	cput		; put cursor at (0,0)

		movlw	'R'
		call	g_out
		movlw	'e'
		call	g_out
		movlw	'v'
		call	g_out
		movlw	' '
		call	g_out
		movlw	'1'
		call	g_out
		movlw	'.'
		call	g_out
		movlw	'4'
		call	g_out
		call	set_addr

		return
;**********************************************************************
clear_row:
		movlw	d'40'
		movwf	count1
clr_loop:
		movlw	0
		call	dput
		movlw	h'c0'
		call	cput

		decfsz  count1, F
		goto    clr_loop
		return
;**********************************************************************
clear_screen:
		movlw	h'40'
		movwf	count1
		movlw	h'2'
		movwf	count2

cls_loop:
		movlw	0
		call	dput
		movlw	h'c0'
		call	cput

		decfsz  count1, F
		goto    cls_loop
		decfsz	count2, F
		goto	cls_loop
		return
;*****************************************************************
; display set routines for the navtex text display
inc_base:
		movlw	d'40'
		addwf	base_lo, F
		bnc	set_base
		incf	base_hi, F
; write base address to display
set_base:
		movfw	base_lo
		movwf	sbase_lo
		call 	dput
		movfw	base_hi
		movwf	sbase_hi
		call 	dput
		movlw	h'40'
		call	cput		; set text home address
		movfw	y		; cursor screen row w = y
		subwf	row, W		; cursor buffer row w = row -w
		movwf	srow		; srow = row - y
		return
;*****************************************************************
; display the gps / mode screen
set_gbase:
		movlw	d'160'
		call 	dput
		movlw	d'30'
		call 	dput
		movlw	h'40'
		call	cput		; set text home address
		return
;*****************************************************************
; set dsiplay ram write pointer to beginning of next row
inc_addr:
		movlw	d'40'
		addwf	addr_lo, F
		bnc	set_addr
		incf	addr_hi, F
; write ram address to display
set_addr:
		movfw	addr_lo
		call	dput
		movfw	addr_hi
		call	dput
		movlw	h'24'
		call	cput
		return
;*****************************************************************
inc_gaddr:
		movlw	d'40'
		addwf	gaddr_lo, F
		bnc	set_gaddr
		incf	gaddr_hi, F
;*****************************************************************
; set the gps/mode screen write pointer
set_gaddr:
		movfw	gaddr_lo
		call 	dput
		movfw	gaddr_hi
		call 	dput
		movlw	h'24'
		call	cput		; set text writing address
		return
;*****************************************************************
init_gaddr:
		movlw	d'160'
		movwf	gaddr_lo
		movlw	d'30'
		movwf	gaddr_hi
		goto	set_gaddr

;*********************************************************
; write one character to the lcd
;*********************************************************
lcd_put:
		movwf	lcdchar

		movfw	y
		subwf	row, W
		movwf	srow

		movfw	lcdchar
		sublw	'D'
		bz	crlf

		btfss	state, LINE_WRAP
		goto	eat_space
line_wrap:
		bcf	state, LINE_WRAP
		movfw	lcdchar
		sublw	' '
		bz	eat_space
		call	move_word
		goto	char_to_lcd
eat_space:
		movf	x, F
		bnz	char_to_lcd
		movfw	lcdchar
		sublw	' '
		bz	set_cursor
char_to_lcd:
		incf	x, F
		movlw	h'20'
		subwf	lcdchar, W	; Adjust to LCD character table
		call	dput
		movlw	h'c0'
		call	cput
check_x:
		movfw	x
		sublw	d'39'
		bc	set_cursor
		bsf	state, LINE_WRAP
		clrf	x
		incf	y, F
		incf	row, F
		call	inc_addr
		goto	check_row
crlf:
		movf	x, F
		bz	set_cursor
		bcf	state, LINE_WRAP
		clrf	x
		incf	y, F
		incf	row, F
		call	inc_addr
check_row:
		movfw	row
		sublw	d'195'
		bnc	wraparound
		movfw	y
		sublw	d'7'
		bnc	newrow
		goto	set_cursor1
set_cursor:
		bcf	state, LINE_WRAP
set_cursor1:
		movfw	x
		call	dput
		movfw	y
		call	dput
		movlw	h'21'
		call	cput	; set_cursor(x,y)
		return

newrow:
		movlw	7
		movwf	y
		incf	srow, F
		call	inc_base
		call    clear_row
		call	set_addr
		goto	set_cursor1		

wraparound:
		clrf	y
		clrf	x
		clrf	base_lo
		clrf	base_hi
		clrf	sbase_lo
		clrf	sbase_hi
		clrf	addr_lo
		clrf	addr_hi
		clrf	row
		clrf	srow
		call	set_base
		call	set_addr
		call	clear_screen
		call	set_addr
		bsf	state, WRAP_ON
		goto	set_cursor

;***********************************************************************
filter_crlf:
		movfw	ch0
		sublw	0xa
		bnz	filter_crlf1
		movlw	' '
		movwf	ch0
filter_crlf1:
		movfw	ch0
		sublw	0xd
		bnz	filter_crlf2
		movlw	' '
		movwf	ch0
filter_crlf2:
		return
;***********************************************************************
serial_out:
		bsf	STATUS, RP0
		btfss	TXSTA, TRMT	; Wait for TX register to become empty
		goto	$-1
		bcf	STATUS, RP0
		movwf	TXREG		; send data to serial line
		return
;*********************************************************
; filter messages
; find zczc_abxy
; zczc_ is start of message
; a     is station id
; b     is message type
; xy    is message number
;
; nnnn  is end of message
; THE MODE SCREEN
; Station
; ST1:*		Select the first station id here. a-z, * means any station
; ST2:*		Select the second station id here, * has no meaning here	
; ST3:*         Select the third station here, * has no meaning here
; Message
; ACFGHIJKLZ
; ynnnnnnnnn
; Select the message types here. BDE are always received
; In addition ACFLZ may be received, the others are not supported
; A - Navigational warning
; B - Meterological warning
; C - Ice report
; D - Search and rescue information / piracy and armed robbery
; E - Meteorologial forecast
; F - Pilot message
; G - Decca message
; H - Loran-C message
; I - Omega message
; J - Differential omega message
; K - Other electronic navigational aid and system message
; L - Navigational warning
; Z - QRU (no message at hand)
;
; The serial command interface
; st1=[a,*] 
; st2=[a,*]
; st3=[a,*]
; msg_a=[y,n]
; .
; .
; .
; msg_z=[y,n]
; print
; help

; Here are the north european stations on 518 KHz.
; UTC schedule.
; !                   ID
; !                   ! Call sign
; !                   ! !   Country
; !                   ! !   !   Station Name
; !                   ! !   !   !             Latitude     Longitude
; 00,04,08,12,16,2010 B LGP NOR Bod          67 16 29 N   14 23 29 E   
; 00,04,08,12,16,2030 D SAG SWE Gothenburg    57 06 N      12 23 E 
; 01,05,09,13,17,2100 G GCC GBR Cullercoats   55 02 N      01 26 W   
; 01,05,09,13,17,2110 H SAH SWE Hrnsand     64 28 N      21 36 E 
; 01,05,09,13,17,2130 J SAA SWE Karlskrona    55 29 N      14 19 E 
; 01,05,09,13,17,2140 K GNI GBR Niton         50 35 N      01 18 W   
; 01,05,09,13,17,2150 L LGQ NOR Rogaland      58 39 23 N   05 36 17 E   
; 02,06,10,14,18,2200 M OST BEL Ostend        51 11 N      02 48 E   
; 02,06,10,14,18,2210 N LGD NOR rlandet      63 40 N      09 33 E   
; 02,06,10,14,18,2220 O GPK GBR Portpatrick   54 51 N      05 07 W   
; 02,06,10,14,18,2230 P PBK HOL Netherlands   52 05 45 N   04 15 29 E 
; 02,06,10,14,18,2240 Q EJM IRL Malin Head    55 22 N      07 21 W   
; 02,06,10,14,18,2250 R TFA ISL Reykjavik     64 05 N      21 51 W   
; 03,07,11,15,19,2300 S GNI GBR Niton         50 35 N      01 18 W   
; 03,07,11,15,19,2310 T OST BEL Ostend        51 11 N      02 48 E   
; 03,07,11,15,19,2320 U ESA EST Tallinn       59 30 N      24 30 E   
; 03,07,11,15,19,2340 W EJK IRL Valentia      51 56 N      10 21 W   
; 03,07,11,15,19,2350 X TFA ISL Reykjavik     64 05 N      21 51 W   
;**************************************************************************
filter:
		movfw	rxasc
		sublw	'A'		; No Phasing signal into the fifo
		bz	filter_ret

		movfw	rxasc
		sublw	'B'		; No Phasing signal into the fifo
		bz	filter_ret

					; advance the fifo
		movlw	d'20'
		movwf	count1		; moves also rxasc to ch0 !
		movlw	ch18
		movwf	FSR
filter1:
		movfw	INDF
		incf	FSR, F
		movwf	INDF
		decf	FSR, F
		decf	FSR, F
		decfsz	count1, F
 		goto	filter1
					; search for zczc_<st_id><msg_type>
		movfw	ch8
		sublw	'z'
		bnz	chk_nnnn

		movfw	ch7
		sublw	'c'
		bnz	chk_nnnn

		movfw	ch6
		sublw	'z'
		bnz	chk_nnnn

		movfw	ch5
		sublw	'c'
		bnz	chk_nnnn

		movfw	ch4
		sublw	' '
		bnz	chk_nnnn
f_st_id1:
		movlw	stid1
		movwf	eeaddr
		call	get_eeprom
		sublw	'*'
		bz	f_msgtype_e
		movfw	eedata
		subwf	ch3, W
		bz	f_msgtype_e
f_st_id2:
		movlw	stid2
		movwf	eeaddr
		call	get_eeprom
		subwf	ch3, W
		bz	f_msgtype_e
f_st_id3:
		movlw	stid3
		movwf	eeaddr
		call	get_eeprom
		subwf	ch3, W
		bnz	set_msgstate_0

f_msgtype_e:
		movlw	'e'			; Weather forecast
		subwf	ch2, W
		bz	f_msgstate
f_msgtype_b:
		movlw	'b'			; Meteorogical warning
		subwf	ch2, W
		bz	f_msgstate
f_msgtype_d:
		movlw	'd'			; Search and rescue
		subwf	ch2, W
		bz	f_msgstate
f_msgtype_a:
		movlw	msg_a
		movwf	eeaddr
		call	get_eeprom
		sublw	'y'
		bnz	f_msgtype_c
		movlw	'a'
		subwf	ch2, W
		bz	f_msgstate		
f_msgtype_c:
		movlw	msg_c
		movwf	eeaddr
		call	get_eeprom
		sublw	'y'
		bnz	f_msgtype_f
		movlw	'c'
		subwf	ch2, W
		bz	f_msgstate		
f_msgtype_f:
		incf	eeaddr, F
		call	get_eeprom
		sublw	'y'
		bnz	f_msgtype_g
		movlw	'f'
		subwf	ch2, W
		bz	f_msgstate		
f_msgtype_g:
		incf	eeaddr, F
		call	get_eeprom
		sublw	'y'
		bnz	f_msgtype_h
		movlw	'g'
		subwf	ch2, W
		bz	f_msgstate		
f_msgtype_h:
		incf	eeaddr, F
		call	get_eeprom
		sublw	'y'
		bnz	f_msgtype_i
		movlw	'h'
		subwf	ch2, W
		bz	f_msgstate		
f_msgtype_i:
		incf	eeaddr, F
		call	get_eeprom
		sublw	'y'
		bnz	f_msgtype_j
		movlw	'i'
		subwf	ch2, W
		bz	f_msgstate		
f_msgtype_j:
		incf	eeaddr, F
		call	get_eeprom
		sublw	'y'
		bnz	f_msgtype_k
		movlw	'j'
		subwf	ch2, W
		bz	f_msgstate		
f_msgtype_k:
		incf	eeaddr, F
		call	get_eeprom
		sublw	'y'
		bnz	f_msgtype_l
		movlw	'k'
		subwf	ch2, W
		bz	f_msgstate		
f_msgtype_l:
		incf	eeaddr, F
		call	get_eeprom
		sublw	'y'
		bnz	f_msgtype_z
		movlw	'l'
		subwf	ch2, W
		bz	f_msgstate		
f_msgtype_z:
		incf	eeaddr, F
		call	get_eeprom
		sublw	'y'
		bnz	set_msgstate_0
		movlw	'z'
		subwf	ch2, W
		bnz	set_msgstate_0		
f_msgstate:
		btfsc	state, MSGSTATE
		goto	chk_nnnn
					; state was 0 and
					; it was an approved start of message
					; print out the the string 
		bsf	state, MSGSTATE	; msgstate = 1 receive message
					; print message identification
		movlw	'D'		; CRLF
		call	lcd_put

		movlw	9
		movwf	count1
		movlw	ch8
		movwf	FSR
filter2:
		movfw	INDF
		call	serial_out

		call	filter_crlf

		movfw	INDF
		call	lcd_put
		decf	FSR, F
		decfsz	count1, F
 		goto	filter2	

		movlw	'D'		; CRLF
		call	lcd_put
		return

					; search for nnnn
set_msgstate_0:
		bcf	state, MSGSTATE
chk_nnnn:
		movfw	ch3
		sublw	'n'
		bnz	c_out
		movfw	ch2
		sublw	'n'
		bnz	c_out
		movfw	ch1
		sublw	'n'
		bnz	c_out
		movfw	ch0
		sublw	'n'
		bnz	c_out

		btfss	state, MSGSTATE
		return

		movfw	ch0
		call	serial_out

		movlw	0xd
		call	serial_out

		movlw	0xa
		call 	serial_out

		movfw	ch0
		call	lcd_put

		movlw	'D'		; CRLF
		call	lcd_put

		bcf	state, MSGSTATE	; msgstate = 0, end of message. stop printing
		return

c_out:
		btfss	state, MSGSTATE
		goto	msgstate_0

		movfw	ch0
		call	serial_out

		call	filter_crlf
		movfw	ch0
		call	lcd_put	
filter_ret:
msgstate_0:
		return
;***********************************************************************
move_word:
		movfw	ch1
		sublw	' '
		btfsc	STATUS, Z
		return			; return if previous line ended in space
		incf	x, F
					; find space on previous line
		movlw	d'18'
		movwf	count1
		movlw	ch2
		movwf	FSR
move_word0:
		movfw	INDF
		sublw	' '
		bz		move_word1
		incf	x, F
		incf	FSR, F
		decfsz	count1, F
 		goto	move_word0	

		clrf	x
		return			; return if no space was found

move_word1:				; space was found
					; set writing mode to decrement the address pointer
					; write 'count1' spaces
					; set writing mode to increment
					; restore the write address by call set_addr
					; write the string on the next row
		movfw	x
		movwf	count1		; setup the amount of backspace
		incf	count1, F
move_word2:
		movlw	0
		call	dput
		movlw	h'c2'		; write and decrease the address pointer
		call	cput
		decfsz  count1, F	; write as many zeroes as needed
		goto	move_word2

		call	set_addr	; restore the address pointer to the beginning of the row 

		movlw	ch0
		addwf	x, W
		movwf	FSR		; point to first character to print

		movfw	x
		movwf	count1		; set the count of characters to print
move_word3:
		movlw	h'20'
		subwf	INDF, W
		call	dput
		movlw	h'c0'
		call	cput
		decf	FSR, F
		decfsz  count1, F
		goto	move_word3

		return
;***************************************************************
set_mode_cursor:
		movfw	mx
		call	dput
		movfw	my
		call	dput
		movlw	h'21'
		call	cput
		return
;*********************************************************
; Check if all or selected messages should be displayed
mode:
		movf	k_mode, F
		bnz	led_on

		movf	s_delay, F
		bnz	mode_ret

		incf	s_delay, F
		incf	set_mode, F
		bcf	PORTC, LED	; led is off when key is pressed
		movlw	4
		movwf	d_delay
		movf	set_mode, W
		sublw	d'14'
		bz	mode_end
		goto	mode_branch	; go to the branch table
mode_end:
		call	init_gaddr
		call	clear_screen
		clrf	set_mode
		call	set_base
		call	set_cursor1
		bcf	state, SCROLL_MODE	; make sure nmea is displayed
led_on:
		movfw	k_mode
		andwf	k_up, W
		andwf	k_down, W
		bz	mode_ret
led_on1:
		movf	rx_i, F
		btfsc	STATUS, Z   
		bsf	PORTC, LED	; led is on after key has been released
mode_ret:
		return
st_out:
		movlw	'S'
		call	g_out
		movlw	'T'
		call	g_out
		return
set_mode_1:
		movlw	h'97'
		call	cput		; text on, cursor blinking, graphics off
		movlw	h'a1'
		call	cput		; two line cursor
		movlw	4
		movwf	mx
		clrf	my
		call	set_mode_cursor
		movlw	stid1
		movwf	mode_p
		call	init_gaddr
		call	clear_screen
		call	set_gaddr
		call	set_gbase
set_mode_st1:
		call	st_out
		movlw	'1'
		call	g_out
set_mode_stn:
		movlw	':'
		call	g_out
		movfw	mode_p
		movwf	eeaddr
		call	get_eeprom
		call	put_lcd
		goto	mode_ret
set_mode_2:
		incf	my, F
		call	set_mode_cursor
		movlw	stid2
		movwf	mode_p
		call	inc_gaddr
		call	st_out
		movlw	'2'
		call	g_out
		goto	set_mode_stn
set_mode_3:
		incf	my, F
		call	set_mode_cursor
		movlw	stid3
		movwf	mode_p
		call	inc_gaddr
		call	st_out
		movlw	'3'
		call	g_out
		goto	set_mode_stn
set_mode_4:				; A
		clrf	mx
		incf	my, F
		incf	my, F
		call	set_mode_cursor
		call	inc_gaddr
		movlw	'A'
		call	g_out
		movlw	'C'
		call	g_out
		movlw	'F'
		call	g_out
		movlw	'G'
		call	g_out
		movlw	'H'
		call	g_out
		movlw	'I'
		call	g_out
		movlw	'J'
		call	g_out
		movlw	'K'
		call	g_out
		movlw	'L'
		call	g_out
		movlw	'Z'
		call	g_out
		call	inc_gaddr
		movlw	msg_a
		movwf	mode_p
		movwf	eeaddr
		movlw	d'10'
		movwf	count1
set_mode_4_1:
		call	get_eeprom
		call	g_out
		incf	eeaddr, F
		decfsz	count1, F
		goto	set_mode_4_1
		call	set_gaddr
		goto	mode_ret
set_mode_5:				; CFGHIJKLZ
		incf	mx, F
		call	set_mode_cursor
		movfw	mode_p
		movwf	eeaddr
		call	get_eeprom
		call	g_out
		incf	mode_p, F
		goto	mode_ret
;*********************************************************
put_lcd:				; Adjust to LCD character table
		addlw	h'e0'		; W = W - h'20'
		call	dput
		movlw	h'c4'
		call	cput
		return
;*********************************************************
set_mode_ud_st:
		movf	k_down, F
		bz	set_mode_down_stn
		movf	k_up, F
		bz	set_mode_up_stn
		return
set_mode_up_stn:
		movfw	mode_p
		call	get_eeprom
		movwf	last_mode_char
		sublw	'*'
		bz	set_mode_up_a
		movfw	last_mode_char
		sublw	'y'
		bc	set_mode_up_stn1
		movlw	'*'
		movwf	last_mode_char
		goto	set_mode_up_stn2
set_mode_up_a:
		movlw	h'60'
		movwf	last_mode_char
set_mode_up_stn1:
		incf	last_mode_char, F
set_mode_up_stn2:
		movfw	last_mode_char
		movwf	eedata
		movfw	mode_p
set_mode_up_down_n:
		movwf	eeaddr
		call	put_eeprom
		movfw	last_mode_char
		call	put_lcd
		return

set_mode_down_stn:
		movfw	mode_p
		call	get_eeprom
		movwf	last_mode_char
		sublw	'*'
		bz	set_mode_down_z
		movfw	last_mode_char
		sublw	h'61' 		; a - last_mode_char
		bnc	set_mode_down_stn1
		movlw	'*'
		movwf	last_mode_char
		goto	set_mode_down_stn2
set_mode_down_z:
		movlw	'{'
		movwf	last_mode_char
set_mode_down_stn1:
		decf	last_mode_char, F
set_mode_down_stn2:
		movfw	last_mode_char
		movwf	eedata
		movfw	mode_p
		goto	set_mode_up_down_n
;**********************************************************
set_mode_ud_msg_n:
		movfw	mode_p
		movwf	eeaddr
		call	get_eeprom
		sublw	'y'
		bnz	set_mode_ud_y
		movlw	'n'
		goto	set_mode_ud_save
set_mode_ud_y:
		movlw	'y'
set_mode_ud_save:
		movwf	last_mode_char
		movwf	eedata
		movfw	mode_p
		movwf	eeaddr
		call	put_eeprom
		movfw	last_mode_char
		call	put_lcd
		return
;*********************************************************
; check if display should be scrolled up or down
scroll:
		movf	s_delay, F
		bnz	scroll_ret
		incf	s_delay, F
		movf	k_up, F
		bz	scroll_up
		movf	k_down, F
		bz	scroll_down
		goto	led_on

scroll_up:
		bcf	PORTC, LED	; Led is off if key is pressed
		movf	set_mode, F
		bnz	set_mode_branch
		bsf	state, SCROLL_MODE
		call	scroll_set

		movlw	2
		movwf	d_delay

		movlw	h'94'
		call	cput		; text on, cursor off, graphics off

					; if (srow == row) return;
		movf	row, W
		subwf	srow, W
		bz	scroll_ret 

					;   if (srow != 0) {
		movf	srow, F
		bz	su_wrap
					;	srow--;
		decf	srow, F
					;	sbase = sbase - 40
		movlw	d'40'
		subwf	sbase_lo, F
		btfss	STATUS, C
		decf	sbase_hi, F
		goto	scroll_set
su_wrap:
		btfss	state, WRAP_ON
		goto	scroll_ret
					;	if (row < 188) {
		movlw	d'188'
		subwf	row, W
		btfsc	STATUS, C
		goto	scroll_ret
					;	   srow = 188
		movlw	d'188'
		movwf	srow
					;	   sbase = 188*40
		movlw	d'96'
		movwf	sbase_lo
		movlw	d'29'
		movwf	sbase_hi
		goto	scroll_set
;***************************************************************************
scroll_down:
		bcf	PORTC, LED	; Led is off if key is pressed
		movf	set_mode, F
		bnz	set_mode_branch
		call	scroll_set

		movlw	2
		movwf	d_delay
		movlw	h'94'
		call	cput		; text on, cursor off, graphics off

					; if (srow == (row - y)) return;
		movfw	y			; cursor screen row w = y
		subwf	row, W			; cursor buffer row w = row -w
		subwf	srow, W			; scroll text first visible row w = srow - w
		bnz	sd_chk_wrap
		bcf     state, SCROLL_MODE	; allow gps display
		return
sd_chk_wrap:					; if (srow < 188) {
		movlw	d'187'
		subwf	srow, W
		btfsc	STATUS, C
		goto	sd_wrap

						;   srow ++
		incf	srow, F
					;   sbase = sbase + 40
		movlw	d'40'
		addwf	sbase_lo, F
		btfsc	STATUS, C
		incf	sbase_hi, F
		goto	scroll_set
sd_wrap:
		clrf	srow
		clrf	sbase_lo
		clrf	sbase_hi
scroll_set:
		movfw	sbase_lo
		call 	dput
		movfw	sbase_hi
		call 	dput
		movlw	h'40'
		call	cput		; set text home address
scroll_ret:
		return
;******************************************************************************
ser_chk_gll:
		movlw	h'94'
		call	cput		; text on, cursor off, graphics off

		movlw	rx3
		movwf	FSR

		movfw	INDF
		sublw	'G'
		bnz	ser_chk_vtg
		incf	FSR, F
		movfw	INDF
		sublw	'L'
		bnz	ser_chk_vtg
		incf	FSR, F
		movfw	INDF
		sublw	'L'
		bnz	ser_chk_vtg
		movlw	3
		movwf	nmea_cmd
		movlw	d'160'
		call	dput
		movlw	d'30'
		call	dput
		movlw	h'24'
		call	cput
		goto	get1bit_ret
ser_chk_vtg:
		movlw	rx3
		movwf	FSR

		movfw	INDF
		sublw	'V'
		bnz	ser_chk_apb
		incf	FSR, F
		movfw	INDF
		sublw	'T'
		bnz	ser_chk_apb
		incf	FSR, F
		movfw	INDF
		sublw	'G'
		bnz	ser_chk_apb
		movlw	4
		movwf	nmea_cmd
		movlw	d'240'
		call	dput
		movlw	d'30'
		call	dput
		movlw	h'24'
		call	cput
		goto	get1bit_ret
ser_chk_apb:
		movlw	rx3
		movwf	FSR

		movfw	INDF
		sublw	'A'
		bnz	get1bit_ret
		incf	FSR, F
		movfw	INDF
		sublw	'P'
		bnz	get1bit_ret
		incf	FSR, F
		movfw	INDF
		sublw	'B'
		bnz	get1bit_ret
		movlw	5
		movwf	nmea_cmd
		movlw	d'64'
		call	dput
		movlw	d'31'
		call	dput
		movlw	h'24'
		call	cput
		goto	get1bit_ret
;***********************************************************************
g_out:
		movwf	gchar
		addlw	h'e0'	; Adjust to LCD character table W=W-h'20'
		call	dput
		movlw	h'c0'
		call	cput
		movfw	gchar
		return
;***********************************************************************
display_element_a:
		movlw	rx0
		movwf	FSR
display_el_a_loop:
		movfw	INDF
		sublw	','
		bz	disp_elem_a_ret
		movfw	INDF
		sublw	'*'
		bz	disp_elem_a_ret
		movfw	INDF
		call	g_out
		incf	FSR, F
		goto	display_el_a_loop

disp_elem_a_ret:
		movlw	' '
		call	g_out
		return
;***********************************************************************
display_element_b:
		movlw	rx0
		movwf	FSR

display_el_b_loop
		movfw	INDF
		sublw	'.'
		bz	disp_elem_b_ret
		movfw	INDF
		call	g_out
		incf	FSR, F
		goto	display_el_b_loop

disp_elem_b_ret:
		incf	FSR, F
		return
;***********************************************************************
; GLL parameters
;***********************************************************************
disp_lat:
		movlw	'L'
		call	g_out
		movlw	'A'
		call	g_out
		movlw	'T'
		call	g_out
		movlw	':'
		call	g_out

		call	display_element_a	; Latitude
		goto	get1bit_ret
disp_lat1:
		call	display_element_a	; North Oder South
		goto	get1bit_ret
disp_lon:
		movlw	'L'
		call	g_out
		movlw	'O'
		call	g_out
		movlw	'N'
		call	g_out
		movlw	':'
		call	g_out

		call	display_element_a	; Longitude		
		goto	get1bit_ret
disp_lon1:
		call	display_element_a	; East Oder West
		goto	get1bit_ret
disp_utc:
		movlw	d'184'
		call	dput
		movlw	d'31'
		call	dput
		movlw	h'24'
		call	cput

		movlw	'U'
		call	g_out
		movlw	'T'
		call	g_out
		movlw	'C'
		call	g_out
		movlw	':'
		call	g_out
disp_time:
		call	display_element_b	; Time
		goto	get1bit_ret
;***********************************************************************
disp_track:
		movlw	'T'
		call	g_out
		movlw	'R'
		call	g_out
		movlw	'K'
		call	g_out
		movlw	':'
		call	g_out
		call	display_element_a	; Track
		goto	get1bit_ret
disp_track1:
		call	display_element_a	; Magnetic/True
		goto	get1bit_ret
disp_speed:
		movlw	'S'
		call	g_out
		movlw	'P'
		call	g_out
		movlw	'D'
		call	g_out
		movlw	':'
		call	g_out
		call	display_element_a	; Speed
		movlw	'K'
		call	g_out
		movlw	't'
		call	g_out
		movlw	' '
		call	g_out
		call	g_out
		call	g_out
		call	g_out		
		goto	get1bit_ret

;***********************************************************************
; Auto Pilot B message
;***********************************************************************
disp_xte:
		movlw	'X'
		call	g_out
		movlw	'T'
		call	g_out
		movlw	'E'
		call	g_out
		movlw	':'
		call	g_out
		call	display_element_a	; Cross Track error
		goto	get1bit_ret
disp_dts:
		call	display_element_a	; Direction to steer
		goto	get1bit_ret
disp_xteu:
		call	display_element_a	; XTE units
		goto	get1bit_ret
disp_status1:
		call	display_element_a	; Status A = arrival circle entered
		goto	get1bit_ret
disp_status2:
		call	display_element_a	; Status A = perpendicular passed att waypoint
		call	g_out
		call	g_out
		call	g_out		
		goto	get1bit_ret
disp_bod:
		movlw	d'104'
		call	dput
		movlw	d'31'
		call	dput
		movlw	h'24'
		call	cput
		movlw	'B'
		call	g_out
		movlw	'O'
		call	g_out
		movlw	'D'
		call	g_out
		movlw	':'
		call	g_out
		call	display_element_a	; Bearing origin to waypoint
		goto	get1bit_ret
disp_bod1:
		call	display_element_a	; M/T
		goto	get1bit_ret
disp_bpd:
		movlw	'B'
		call	g_out
		movlw	'P'
		call	g_out
		movlw	'D'
		call	g_out
		movlw	':'
		call	g_out
		call	display_element_a	; Bearing, present position to waypoint
		goto	get1bit_ret
disp_bpd1:
		call	display_element_a	; M/T
		goto	get1bit_ret
disp_hds:
		movlw	'H'
		call	g_out
		movlw	'D'
		call	g_out
		movlw	'S'
		call	g_out
		movlw	':'
		call	g_out
		call	display_element_a	; Heading to steer
		goto	get1bit_ret
disp_hds1:
		call	display_element_a	; M/T
		call	g_out
		call	g_out
		call	g_out		
		goto	get1bit_ret
;***********************************************************************
check_cmd:
		clrf	nmea_cmd
		movlw	rx0
		movwf	FSR
chk_cmd_0:
		movfw	INDF
		sublw	'h'
		bz	do_help
		movfw	INDF
		sublw	'p'
		bz	do_print
		movfw	INDF
		sublw	's'
		bz	do_st
		movfw	INDF
		sublw	'm'
		bz	do_msg
chk_cmd_help:
chk_cmd_ret:
		goto	get1bit_ret
;**********************************************************************
;Print zero terminated string from EEPROM to the serial port
see_out:
		movwf	eeaddr
see_out_1:
		call	get_eeprom
		bz	see_out_ret
		movfw	eedata
		call	serial_out

		incf	eeaddr, F
		goto	see_out_1
see_out_ret:
		return	
;***********************************************************************
do_help:
		movlw	help_text
		call	see_out
		goto	get1bit_ret
do_print:
		movlw	'1'
		call	serial_out
		movlw	'2'
		call	serial_out
		movlw	'3'
		call	serial_out
		movlw	'a'
		call	serial_out
		movlw	'c'
		call	serial_out
		movlw	'f'
		call	serial_out
		movlw	'g'
		call	serial_out
		movlw	'h'
		call	serial_out
		movlw	'i'
		call	serial_out
		movlw	'j'
		call	serial_out
		movlw	'k'
		call	serial_out
		movlw	'l'
		call	serial_out
		movlw	'z'
		call	serial_out
		movlw	0xd
		call	serial_out
		movlw	0xa
		call	serial_out

		movlw	stid1
		call	see_out

		goto	get1bit_ret
;*********************************************************
do_st:
		incf	FSR, F
		movfw	INDF
		sublw	't'
		bnz	get1bit_ret
		incf	FSR, F
		movfw	INDF
		sublw	'1'
		bz	do_st1
		movfw	INDF
		sublw	'2'
		bz	do_st2
		movfw	INDF
		sublw	'3'
		bnz	get1bit_ret

		movlw	stid3
		movwf	eeaddr
		goto	do_st4
do_st2:
		movlw	stid2
		movwf	eeaddr
		goto	do_st4
do_st1:
		movlw	stid1
		movwf	eeaddr
do_st4:
		incf	FSR, F
		incf	FSR, F
		movfw	INDF
		movwf	eedata
		call	put_eeprom
		goto	get1bit_ret
;**********************************************************************
do_msg:
		movlw	4
		addwf	FSR, F
		movlw	msg_a
		movwf	eeaddr

		movfw	INDF
		sublw	'a'
		bz	do_msg_1

		incf	eeaddr, F
		movfw	INDF
		sublw	'c'
		bz	do_msg_1

		incf	eeaddr, F
		movfw	INDF
		sublw	'f'
		bz	do_msg_1

		incf	eeaddr, F
		movfw	INDF
		sublw	'g'
		bz	do_msg_1

		incf	eeaddr, F
		movfw	INDF
		sublw	'h'
		bz	do_msg_1

		incf	eeaddr, F
		movfw	INDF
		sublw	'i'
		bz	do_msg_1

		incf	eeaddr, F
		movfw	INDF
		sublw	'j'
		bz	do_msg_1

		incf	eeaddr, F
		movfw	INDF
		sublw	'k'
		bz	do_msg_1

		incf	eeaddr, F
		movfw	INDF
		sublw	'l'
		bz	do_msg_1

		incf	eeaddr, F
		movfw	INDF
		sublw	'z'
		bz	do_msg_1
		goto	get1bit_ret

do_msg_1:
		incf	FSR, F
		incf	FSR, F
		movfw	INDF
		movwf	eedata
		call	put_eeprom
		goto	get1bit_ret
;***********************************************************************
put_eeprom:
		bsf	STATUS, RP1
		bsf	STATUS, RP0
		btfsc	EECON1, WR
		goto	$-1
		bcf	STATUS, RP0
		movfw	eeaddr
		movwf	EEADR
		movfw	eedata
		movwf	EEDATA
		bsf	STATUS, RP0
		bcf	EECON1, EEPGD
		bsf	EECON1, WREN
		bcf	INTCON, GIE
		movlw	0x55
		movwf	EECON2
		movlw	0xaa
		movwf	EECON2
		bsf	EECON1, WR
		bcf	EECON1, WREN
		bsf	INTCON, GIE
		bcf	STATUS, RP0
		bcf	STATUS, RP1
		return
;***********************************************************************
get_eeprom:
		bsf	STATUS, RP1
		bcf	STATUS, RP0
		movfw	eeaddr
		movwf	EEADR
		bsf	STATUS, RP0
		bcf	EECON1, EEPGD
		bsf	EECON1, RD
		bcf	STATUS, RP0
		movf	EEDATA, W
		bcf	STATUS, RP1
		movwf	eedata
		return
;***********************************************************************
sitoasc:
		bsf	PCLATH, 2
		bsf	PCLATH, 1
		bsf	PCLATH, 0
		call	translate
		clrf	PCLATH
		return

		org	0x6ff
translate:
		addwf	PCL, F  ; 
		retlw   0x0	; 0  addr = 0x700
		retlw   0x0	; 1
		retlw   0x0	; 2
		retlw	0x0	; 3
		retlw   0x0	; 4
		retlw   0x0	; 5
		retlw	0x0	; 6
		retlw	0x0	; 7
		retlw	0x0	; 8
		retlw	0x0	; 9
		retlw	0x0	; a
		retlw	0x0	; b
		retlw	0x0	; c
		retlw	0x0	; d
		retlw	0x0	; e
		retlw	0xd	; f  CR 0xd
		retlw	0x0	; 10
		retlw	0x0	; 11
		retlw	0x0	; 12
		retlw	0x0	; 13
		retlw	0x0	; 14
		retlw	0x0	; 15
		retlw	0x0	; 16
		retlw	't'	; 17 T 5
		retlw	0x0	; 18
		retlw	0x0	; 19
		retlw	0x0	; 1a
		retlw	0xa	; 1b LF 0xa
		retlw	0x0	; 1c
		retlw	' '	; 1d SPACE
		retlw	'v'	; 1e V =
		retlw	0x0	; 1f
		retlw	0x0	; 20
		retlw	0x0	; 21
		retlw	0x0	; 22
		retlw	0x0	; 23
		retlw	0x0	; 24
		retlw	0x0	; 25
		retlw	0x0	; 26
		retlw	'b'	; 27 B ?
		retlw	0x0	; 28
		retlw	0x0	; 29
		retlw	0x0	; 2a
		retlw	'_'	; 2b BLANK
		retlw	0x0	; 2c
		retlw	'L'	; 2d LETTERS
		retlw	'x'	; 2e X /
		retlw	0x0	; 2f
		retlw	0x0	; 30
		retlw	0x0	; 31
		retlw	0x0	; 32
		retlw	'B'	; 33 PHASE2
		retlw	0x0	; 34
		retlw	'e'	; 35 E 3
		retlw	'F'	; 36 FIGURES
		retlw	0x0	; 37
		retlw	0x0	; 38
		retlw	'u'	; 39 U 7
		retlw	'q'	; 3a Q 1
		retlw	0x0	; 3b
		retlw	'k'	; 3c K (
		retlw	0x0	; 3d
		retlw	0x0	; 3e
		retlw	0x0	; 3f
		retlw	0x0	; 40
		retlw	0x0	; 41
		retlw	0x0	; 42
		retlw	0x0	; 43
		retlw	0x0	; 44
		retlw	0x0	; 45
		retlw	0x0	; 46
		retlw	'o'	; 47 O 9
		retlw	0x0	; 48
		retlw	0x0	; 49
		retlw	0x0	; 4a
		retlw	'h'	; 4b H #
		retlw	0x0	; 4c
		retlw	'n'	; 4d N ,
		retlw	'm'	; 4e M .
		retlw	0x0	; 4f
		retlw	0x0	; 50
		retlw	0x0	; 51
		retlw	0x0	; 52
		retlw	'l'	; 53 L )
		retlw	0x0	; 54
		retlw	'r'	; 55 R 4
		retlw	'g'	; 56 G &
		retlw	0x0	; 57
		retlw	0x0	; 58
		retlw	'i'	; 59 I 8
		retlw	'p'	; 5a P 0
		retlw	0x0	; 5b
		retlw	'c'	; 5c C :
		retlw	0x0	; 5d
		retlw	0x0	; 5e
		retlw	0x0	; 5f
		retlw	0x0	; 60
		retlw	0x0	; 61
		retlw	0x0	; 62
		retlw	'z'	; 63 Z +
		retlw	0x0	; 64
		retlw	'd'	; 65 D $
		retlw	0x0	; 66
		retlw	0x0	; 67
		retlw	0x0	; 68
		retlw	's'	; 69 S \
		retlw	'y'	; 6a Y 6
		retlw	0x0	; 6b
		retlw	'f'	; 6c F ?
		retlw	0x0	; 6d
		retlw	0x0	; 6e
		retlw	0x0	; 6f
		retlw	0x0	; 70
		retlw	'a'	; 71 A -
		retlw	'w'	; 72 W 2
		retlw	0x0	; 73
		retlw	'j'	; 74 J 7 BELL
		retlw	0x0	; 75
		retlw	0x0	; 76
		retlw	0x0	; 77
		retlw	'A'	; 78 PHASE1
		retlw	0x0	; 79
		retlw	0x0	; 7a
		retlw	0x0	; 7b
		retlw	0x0	; 7c
		retlw	0x0	; 7d
		retlw	0x0	; 7e
		retlw	0x0	; 7f
		retlw	0x0	; 0
		retlw	0x0	; 1
		retlw   0x0	; 2
		retlw	0x0	; 3
		retlw   0x0	; 4
		retlw   0x0	; 5
		retlw	0x0	; 6
		retlw	0x0	; 7
		retlw	0x0	; 8
		retlw	0x0	; 9
		retlw	0x0	; a
		retlw	0x0	; b
		retlw	0x0	; c
		retlw	0x0	; d
		retlw	0x0	; e
		retlw	0xd	; f  CR 0xd
		retlw	0x0	; 10
		retlw	0x0	; 11
		retlw	0x0	; 12
		retlw	0x0	; 13
		retlw	0x0	; 14
		retlw	0x0	; 15
		retlw	0x0	; 16
		retlw	'5'	; 17 T 5
		retlw	0x0	; 18
		retlw	0x0	; 19
		retlw	0x0	; 1a
		retlw	0xa	; 1b LF
		retlw	0x0	; 1c
		retlw	' '	; 1d SPACE
		retlw	'='	; 1e V =
		retlw	0x0	; 1f
		retlw	0x0	; 20
		retlw	0x0	; 21
		retlw	0x0	; 22
		retlw	0x0	; 23
		retlw	0x0	; 24
		retlw	0x0	; 25
		retlw	0x0	; 26
		retlw	'?'	; 27 B ?
		retlw	0x0	; 28
		retlw	0x0	; 29
		retlw	0x0	; 2a
		retlw	'_'	; 2b BLANK
		retlw	0x0	; 2c
		retlw	'L'	; 2d LETTERS
		retlw	'/'	; 2e X /
		retlw	0x0	; 2f
		retlw	0x0	; 30
		retlw	0x0	; 31
		retlw	0x0	; 32
		retlw	'B'	; 33 PHASE2
		retlw	0x0	; 34
		retlw	'3'	; 35 E 3
		retlw	'F'	; 36 FIGURES
		retlw	0x0	; 37
		retlw	0x0	; 38
		retlw	'7'	; 39 U 7
		retlw	'1'	; 3a Q 1
		retlw	0x0	; 3b
		retlw	'('	; 3c K (
		retlw	0x0	; 3d
		retlw	0x0	; 3e
		retlw	0x0	; 3f
		retlw	0x0	; 40
		retlw	0x0	; 41
		retlw	0x0	; 42
		retlw	0x0	; 43
		retlw	0x0	; 44
		retlw	0x0	; 45
		retlw	0x0	; 46
		retlw	'9'	; 47 O 9
		retlw	0x0	; 48
		retlw	0x0	; 49
		retlw	0x0	; 4a
		retlw	'#'	; 4b H #
		retlw	0x0	; 4c
		retlw	','	; 4d N ,
		retlw	'.'	; 4e M .
		retlw	0x0	; 4f
		retlw	0x0	; 50
		retlw	0x0	; 51
		retlw	0x0	; 52
		retlw	')'	; 53 L )
		retlw	0x0	; 54
		retlw	'4'	; 55 R 4
		retlw	'&'	; 56 G &
		retlw	0x0	; 57
		retlw	0x0	; 58
		retlw	'8'	; 59 I 8
		retlw	'0'	; 5a P 0
		retlw	0x0	; 5b
		retlw	':'	; 5c C :
		retlw	0x0	; 5d
		retlw	0x0	; 5e
		retlw	0x0	; 5f
		retlw	0x0	; 60
		retlw	0x0	; 61
		retlw	0x0	; 62
		retlw	'+'	; 63 Z +
		retlw	0x0	; 64
		retlw	'$'	; 65 D $
		retlw	0x0	; 66
		retlw	0x0	; 67
		retlw	0x0	; 68
		retlw	'\\'	; 69 S \
		retlw	'6'	; 6a Y 6
		retlw	0x0	; 6b
		retlw	'?'	; 6c F ?
		retlw	0x0	; 6d
		retlw	0x0	; 6e
		retlw	0x0	; 6f
		retlw	0x0	; 70
		retlw	'-'	; 71 A -
		retlw	'2'	; 72 W 2
		retlw	0x0	; 73
		retlw	0x0	; 74 J 7 BELL
		retlw	0x0	; 75
		retlw	0x0	; 76
		retlw	0x0	; 77
		retlw	'A'	; 78 PHASE1
		retlw	0x0	; 79
		retlw	0x0	; 7a
		retlw	0x0	; 7b
		retlw	0x0	; 7c
		retlw	0x0	; 7d
		retlw	0x0	; 7e
		retlw	0x0	; 7f

;************************************************************************
		org		H'2100'

help_text	equ		($ - h'2100')
			de		"stn=[a,*]", 0xd, 0xa
			de		"msg_x=[y,n]", 0xd, 0xa
			de		"print" 0xd,0xa
			de		"help", 0xd,0xa,0 
stid1		equ		$-h'2100'
			de		"*hjyynnnnnnnn", 0xd, 0xa, 0
stid2		equ		stid1+1
stid3		equ		stid1+2
msg_a		equ		stid1+3
msg_c       equ     stid1+4
msg_f		equ		stid1+5
msg_g		equ		stid1+6
msg_h		equ		stid1+7
msg_i		equ		stid1+8
msg_j		equ		stid1+9
msg_k		equ		stid1+0xa
msg_l		equ		stid1+0xb
msg_z		equ		stid1+0xc
version		equ		$-h'2100'
			de		"Rev 1.4"
cr_lf		equ		$-h'2100'
			de		0xd,0xa,0
;************************************************************************
		END                       ; directive 'end of program'
;************************************************************************
		org		0x0800


